// 测试三要素:
// 测试环境
// 测试方法
// 测试结果：同步下的单线程 / 多线程； 异步下的单线程 / 多线程
// 测试工具的编写:
// 可以控制写日志线程数量
// 可以控制写日志的总数量
// 分别对于同步日志器 & 异步日志器进行各自的性能测试
// 需要测试单写日志线程的性能
// 需要测试多写日志线程的性能
// 实现:
// 封装一个接口，传入日志器名称，线程数量，日志数量，单条日志大小。
// 在接口内，创建指定数量的线程，各自负责一部分日志的输出。
// 在输出之前计时开始，在输出完毕后计时结束，所耗时间 = 结束时间 - 起始时间。
// 每秒输出量 = 日志数量 / 总耗时。
// 每秒输出大小 = 日志数量 * 单条日志大小 / 总耗时。
// 注意：异步日志输出这里，我们启动非安全模式，纯内存写入（不去考虑实际落地的时间）
// 性能测试函数，传入日志器名称、线程数量、日志数量和单条日志大小
#include"logger.hpp"
#include"logsys.h"
void bench(const std::string &logger_name, size_t thr_count, size_t msg_count, size_t msg_len) {
    // 1. 获取日志器
    logsys::Logger::ptr logger = logsys::getLogger(logger_name);
    if (logger.get() == nullptr) {
        return;
    }
    std::cout << "测试日志: " << msg_count << " 条，总大小: " << (msg_count * msg_len) / 1024 << " KB\n";

    // 2. 组织指定长度的日志消息，少一个字节用于末尾添加换行
    std::string msg(msg_len - 1, 'A'); 

    // 3. 创建指定数量的线程
    std::vector<std::thread> threads;
    std::vector<double> cost_array(thr_count);
    size_t msg_per_thr = msg_count / thr_count; // 总日志数量/线程数量就是每个线程要输出的日志数量

    for (int i = 0; i < thr_count; i++) {
        threads.emplace_back([&, i]() {
            // 4. 线程函数内部开始计时
            auto start = std::chrono::high_resolution_clock::now();

            // 5. 开始循环写日志
            for (int j = 0; j < msg_per_thr; j++) {
                logger->fatal("%s", msg.c_str());
            }

            // 6. 线程函数内部结束计时
            auto end = std::chrono::high_resolution_clock::now();
            // 正确获取以秒为单位的耗时，原代码注释指出不能用auto，需显式指定单位
            std::chrono::duration<double> cost = end - start; 
            cost_array[i] = cost.count();
            std::cout << "\t线程" << i << ": " << "\t输出数量: " << msg_per_thr << ", 耗时: " << cost.count() << "s" << std::endl;
        });
    }

    for (int i = 0; i < thr_count; i++) {
        threads[i].join();
    }

    // 7. 计算总耗时: 在多线程中，每个线程都会耗费时间，因为线程是并发处理的，因此耗时最高的那个就是总时间
    double max_cost = cost_array[0];
    for (int i = 0; i < thr_count; i++) {
        max_cost = max_cost < cost_array[i]? cost_array[i] : max_cost;
    }
    size_t msg_per_sec = msg_count / max_cost;
    size_t size_per_sec = (msg_count * msg_len) / (max_cost * 1024);

    // 8. 进行输出打印
    std::cout << "\t总耗时: " << max_cost << "s\n";
    std::cout << "\t每秒输出日志数量: " << msg_per_sec << " 条\n";
    std::cout << "\t每秒输出日志大小: " << size_per_sec << " KB\n";
}

void sync_bench() {
    std::unique_ptr<logsys::LoggerBuilder> builder(new logsys::GlobalLoggerBuilder());
    builder->buildLoggerName("sync_logger");
    builder->buildFormatter("%m%n");
    builder->buildLoggerType(logsys::LoggerType::LOGGER_SYNC);
    builder->buildSink<logsys::FileSink>("./logfile/sync.log");
    builder->build();
    bench("sync_logger", 1, 1000000, 100);
}
void async_bench_unsafe() {
    std::unique_ptr<logsys::LoggerBuilder> builder(new logsys::GlobalLoggerBuilder());
    builder->buildLoggerName("async_logger");
    builder->buildFormatter("%m%n");
    builder->buildLoggerType(logsys::LoggerType::LOGGER_ASYNC);
    // builder->buildEnableUnSafeAsync();//开始非安全模式---主要是为了将实际落地时间排除在外
    builder->buildSink<logsys::FileSink>("./logfile/async.log");
    builder->build();
    bench("async_logger", 1, 1000000, 100);
}

// 测试日志: 1000000 条, 总大小: 97656KB
//     线程0: 输出数量:1000000, 耗时:2.26222s
//     总耗时:2.26222s
//     每秒输出日志数量: 442043条
//     每秒输出日志大小: 43168KB

void async_bench_safe() {
    std::unique_ptr<logsys::LoggerBuilder> builder(new logsys::GlobalLoggerBuilder());
    builder->buildLoggerName("async_logger");
    builder->buildFormatter("%m%n");
    builder->buildLoggerType(logsys::LoggerType::LOGGER_ASYNC);
    builder->buildEnableUnSafeAsync();//开始非安全模式---主要是为了将实际落地时间排除在外
    builder->buildSink<logsys::FileSink>("./logfile/async.log");
    builder->build();
    bench("async_logger", 1, 1000000, 100);
}

int main(){
 sync_bench();
}